﻿using Sage.WindowsProcess.Events;
using System.Runtime.Versioning;

namespace Sage.WindowsProcess
{
    /// <summary>
    /// ExternalProcessManager类的异步操作相关部分
    /// </summary>
    public partial class ExternalProcessManager
    {
        /// <summary>
        /// 异步启动外部程序，如果程序尚未运行。
        /// </summary>
        /// <param name="timeout">等待进程启动的超时时间（毫秒）。指定0表示无限等待。</param>
        /// <param name="cancellationToken">可用于取消操作的取消令牌。</param>
        /// <returns>表示异步操作的任务，其结果指示进程是否成功启动。</returns>
        [SupportedOSPlatform("windows")]
        public async ValueTask<bool> StartProcessAsync(int timeout = 30000, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // 检查文件是否存在
            if (!File.Exists(_processPath))
            {
                OnProcessError(new ProcessErrorEventArgs($"启动失败：程序路径不存在 - {_processPath}"));
                return false;
            }

            // 使用Task.Run处理可能需要时间的进程启动
            return await Task.Run(() => StartProcess(timeout), cancellationToken);
        }

        /// <summary>
        /// 异步停止外部程序，如果程序正在运行。
        /// </summary>
        /// <param name="timeout">等待进程退出的超时时间（毫秒）。指定0表示无限等待。</param>
        /// <param name="cancellationToken">可用于取消操作的取消令牌。</param>
        /// <returns>表示异步操作的任务，其结果指示进程是否成功停止。</returns>
        public async ValueTask<bool> StopProcessAsync(int timeout = 5000, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (!IsRunning)
                return true;

            return await Task.Run(() => StopProcess(timeout), cancellationToken);
        }

        /// <summary>
        /// 异步重启正在运行的进程。如果进程未运行，则只启动它。
        /// </summary>
        /// <param name="startTimeout">启动超时（毫秒）</param>
        /// <param name="stopTimeout">停止超时（毫秒）</param>
        /// <param name="cancellationToken">可用于取消操作的取消令牌。</param>
        /// <returns>表示异步操作的任务，其结果指示进程是否成功重启。</returns>
        [SupportedOSPlatform("windows")]
        public async ValueTask<bool> RestartProcessAsync(int startTimeout = 30000, int stopTimeout = 5000, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (IsRunning)
            {
                // 先停止进程
                bool stopped = await StopProcessAsync(stopTimeout, cancellationToken);
                if (!stopped)
                    return false;
            }

            // 然后启动进程
            return await StartProcessAsync(startTimeout, cancellationToken);
        }

        /// <summary>
        /// 异步向进程的标准输入写入数据。
        /// </summary>
        /// <param name="input">要写入的输入字符串。</param>
        /// <param name="cancellationToken">可用于取消操作的取消令牌。</param>
        /// <returns>表示异步操作的任务，其结果指示数据是否成功写入。</returns>
        public async ValueTask<bool> WriteToStandardInputAsync(string input, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (!IsRunning || _process?.StandardInput == null)
                return false;

            return await Task.Run(() => WriteToStandardInput(input), cancellationToken);
        }

        /// <summary>
        /// 异步等待进程退出。
        /// </summary>
        /// <param name="timeout">等待的超时时间（毫秒）。指定-1表示无限等待。</param>
        /// <param name="cancellationToken">可用于取消等待的取消令牌。</param>
        /// <returns>表示异步操作的任务，当进程退出或超时时完成。任务结果指示进程是否在超时前退出。</returns>
        public async Task<bool> WaitForExitAsync(int timeout = -1, CancellationToken cancellationToken = default)
        {
            if (!IsRunning)
                return true; // 进程已经退出或未运行

            // 使用更高效的异步等待模式
            var tcs = new TaskCompletionSource<bool>();
            EventHandler? exitedHandler = null;

            try
            {
                if (_process == null)
                    return true;

                // 创建进程退出事件处理程序
                exitedHandler = (s, e) => tcs.TrySetResult(true);

                // 确保进程启用了事件
                _process.EnableRaisingEvents = true;
                _process.Exited += exitedHandler;

                // 再次检查进程是否已退出（可能在附加事件处理程序后已经退出）
                if (_process.HasExited)
                    return true;

                // 根据超时设置创建等待任务
                if (timeout >= 0)
                {
                    // 使用更现代的异步超时模式
                    try
                    {
                        return await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(timeout), cancellationToken);
                    }
                    catch (TimeoutException)
                    {
                        return false; // 超时
                    }
                }
                else
                {
                    return await tcs.Task.WaitAsync(cancellationToken);
                }
            }
            finally
            {
                // 确保清理事件处理程序
                if (exitedHandler != null && _process != null)
                {
                    try
                    {
                        _process.Exited -= exitedHandler;
                    }
                    catch
                    {
                        // 进程可能已被处置，忽略此处可能的异常
                    }
                }
            }
        }
    }
}
